        TITL DAI FIRMWARE 1EE0B-1EFFF  V1.0  Rev.1
        ORG   :EE0B
*
*
*
**************
* (not used) *
**************
*
L1E245  PUSH  H
        CALL  :D891
*
***********************************************
* LOADA: READ ARRAY DATA FROM TAPE INTO ARRAY *
***********************************************
*
* Reads block(s) from tape into the free RAM space
* and move it afterwards into the array.
*
* Entry: HL: Length of name requested.
*        A:  Variable type.
*        On stack: Address where to dump data.
*
L1E273  PUSH  B
        PUSH  PSW       Save var.type
        LXI   B,:3200   File type in B, C for load
 REM during program
        CALL  :D681     Open read file
        POP   H         Get var.type in H
        CALL  :EFB5     Read var.type from tape
        CMP   H         Correct type ?
        JNZ   :DA1A     Run error 'TYPE MISMATCH'
 REM if not
        CPI   :20
        JZ    :EE38     Jump if string arrays
 REM
* If INT/FPT arrays:
 REM
        POP   H
        XTHL            Get dumpaddr in HL
        XCHG            Get length in HL
        DAD   D         HL is end dump area
        XCHG            in DE; HL is start dump
        CALL  :02D1     Read block from tape
        JNC   :D2B3     Evt run 'LOADING ERROR ..'
L1E246  CALL  :02D4     Stop reading
        LDA   :0040     Get POROM
        JMP   :EFA6     Select ROM bank 0, abort
 REM
* If string arrays:
 REM
L1E247  PUSH  D
        LHLD  :02A5     Get bottom screen RAM
        XCHG            in DE
        LHLD  :02A3     Get begin free RAM space
        PUSH  H
        CALL  :D897     Read block from tape into
 REM free RAM area; evt.run error
        POP   H         Get begin free RAM
        MOV   D,M       )
        INX   H         ) Length of array in DE
        MOV   E,M       )
        INX   H
        JMP   :D6E5     Via D6E5 to 1EE4C
*
L1E248  PUSH  B         Save length array
        PUSH  D
        CALL  :CBA8     Erase stringreference
 REM in heap and symtab
        DCX   H
        DCX   H
        POP   D
        PUSH  H
        LDAX  D
        CALL  :D18B     Get place in heap for string
        PUSH  H
        CALL  :D172     Transfer string into heap
        POP   B
        POP   H         )
        MOV   M,C       ) Length into heap at
        INX   H         ) begin of string
        MOV   M,B       )
        INX   H
        POP   B         Get length array
        DCX   B         ) Update it
        DCX   B         )
        MOV   A,B
        ORA   C
        JNZ   :EE4C     Next string if not ready
        JMP   :EE2F     Stop reading, select ROM
 REM bank 0; abort
*
*
*   ============
*** SOUND MODULE ***
*   ============
*
*
TEMPO   MVI   C,:00     Count SCB
        LXI   H,:01C2   Addr sound control block 0
L1E250  PUSH  H         Preserve addr SCB
        MOV   A,M       Get value of volume counter
        CPI   :FE
        JZ    :EE7E     If FE: No increment (sound
 REM forever)
        JNC   :EF9D     If FF: Goto next block
 REM (sound off)
        INR   M         ) Incr duration count volume
L1E251  INR   A         )
        PUSH  H         Preserve addr SCB
        MOV   B,A       Save incr duration count
        INX   H
        MOV   E,M       ) Get pntr envelope count
        INX   H         ) in DE
        MOV   D,M       )
        LDAX  D         Get envelope duration count
        CMP   B         Comp with volume count
        JNC   :EEB8     Jump if env. not counted out
 REM
* Envelope counted out:
 REM
        XCHG
        XTHL            Addr env.duration on stack;
 REM addr SCB in HL
        MVI   M,:00     Present duration count is 0
        POP   H         Get pntr to env.table
        INX   H         +1
        MOV   A,M       Get next env. duration
        ORA   A         Is it FF ?
        CM    :EF93     Then restart envelope
        MOV   B,A       Env duration in B
        INX   H         Pnts to next pos env table
        MOV   A,M       Value in A
        XCHG
        MOV   M,D       ) Set env pointer in SCB
        DCX   H         ) to new time field
        MOV   M,E       )
        INX   H
        INX   H
        INX   H
        INX   H         HL pnts to vol.multiplier
        PUSH  H
        MOV   L,M       Sound volume *8 in L
        MVI   H,:00
        DAD   H         *16 in HL
        XCHG            Multiplier in DE
        LXI   H,:0080   Init.value
L1E252  DCR   B         Decr. envelope duration
        JM    :EEB1     Jump if ready
        DAD   D         Add multiplier
        JMP   :EEA9     Again
L1E253  MOV   B,H       New eff. volume in B
        POP   H
        INX   H
        MOV   M,B       Set new basic volume
        JMP   :EEBD
 REM
* If envelope not counted out:
 REM
L1E254  POP   D
        INX   H
        INX   H
        INX   H
        INX   H
 REM
* Handle tremolo:
 REM
L1E255  MOV   B,M       Get basic volume in B
        INX   H
        MOV   A,M       Get tremolo count
        ORA   A
        JZ    :EEEB     Jump if no tremolo adj.
        ADI   :01       )
        ACI   :00       ) Incr tremolo count
        MOV   M,A       )
        RAR
        RAR
        RAR
        JNC   :EEDC     No adj. if bit 2 of
 REM <T> is 0
        INR   B         )
        INR   B         ) Else add 4 units to
        INR   B         ) basic volume
        INR   B         )
        RAR
        NOP
        JC    :EEDC     No adjust if bit 2 of
 REM <T> = 0
        MOV   A,B
        SUI   :08       Else: basic vol. -2 units
        MOV   B,A
*
L1E256  NOP
        MOV   A,B       Get updated basic volume
        MVI   B,:00
        ORA   A
        JM    :EEEB     Jump if B1-FF
        MVI   B,:0F
        CMP   B
        JNC   :EEEB     Jump if >=0F (max.value)
        MOV   B,A
*
L1E257  INX   H         Pnts to actual volume
        MOV   A,B       Get new basic volume
        SUB   M         Minus actual volume
        RLC             )
        RAR             )
        CMC             ) New actual volume is
        ACI   :00       ) old one + 0.5
        RLC             ) (difference +/- 1)
        RAR             )
        RAR             )
        ADD   M         )
        MOV   M,A       Store in SCB
        MOV   B,A       and in B
        PUSH  H
        PUSH  B
        LXI   D,:0294   Addr POROM
        LXI   H,:FD04   Addr PORO
        MOV   A,C       Get SCB count
        MVI   C,:F0     Mask for vol. SCB0,SCB2
        RRC
        JNC   :EF12     Jump if SCB0,SCB2
        MVI   C,:0F     Mask for vol. SCB1,NCB
        PUSH  PSW
        MOV   A,B       )
        ADD   A         ) Actual volume into
        ADD   A         ) hinibble for SCB1
        ADD   A         ) and NCB
        ADD   A         )
        MOV   B,A       )
        POP   PSW       
L1E258  RAR
        JNC   :EF18     Jump if SCB0,SCB1
        INX   D         ) POR0M+1,POR0+1
        INX   H         ) for SCB2,NCB
L1E259  LDAX  D         Get POR0M,POR1M
        ANA   C         Only reqd volume
        ORA   B         Update it
        STAX  D         Back in POR0M,POR1M
        MOV   M,A       and in POR0,POR1
        POP   B
        POP   H
        INR   C         SCB count +1
        MOV   A,C
        CPI   :04
        JZ    :EFA4     Ready if block was NCB
 REM
 REM
 REM
        INX   H
        MOV   A,M       Get glissando flag
        DCR   A
        JM    :EF8B     Ready if end period
 REM reached
        INX   H
        MOV   E,M       ) Get current period of
        INX   H         ) output in DE
        MOV   D,M       )
        PUSH  H
        INX   H
        MOV   A,M       ) Get reqd final period
        INX   H         ) in HL
        MOV   H,M       )
        MOV   L,A
        JNZ   :EF3B     Jump if end period not
 REM reached
        MOV   D,H       ) HL=DE if 'set freq'
        MOV   E,L       )
L1E260  CALL  :DE14     Compare HL-DE
        PUSH  PSW
        PUSH  D
        JNC   :EF44     Jump if final period >=
 REM current period
        XCHG            Else exchange values
L1E261  CALL  :DE1A     Calc difference in HL
        POP   D
        PUSH  D
        PUSH  H
        XCHG
        MVI   E,:40     )
L1E262  MOV   A,L       )
        RAL             )
        MOV   L,A       )
        MOV   A,H       )
        RAL             ) HL = HL SHL 6
        MOV   H,A       )
        MOV   A,E       )
        RAL             )
        MOV   E,A       )
        JNC   :EF4D
        MOV   L,H       ) HL = 1/64 orig. value
        MOV   H,E       )
        MOV   A,H
        ORA   L
        JNZ   :EF61
        INX   H
L1E263  POP   D
        CALL  :DE14     Compare HL-DE
        MVI   B,:02
        JC    :EF6D     Jump if DE > HL
        MVI   B,:00
        XCHG
L1E264  POP   D
        POP   PSW
        JNC   :EF75
        CALL  :DE26     HL is its 2-compl.
L1E265  DAD   D
        XCHG
        POP   H
        MOV   M,D       ) Set new current period
        DCX   H         )
        MOV   M,E       )
        DCX   H
        MOV   M,B       Set glissando flag
        PUSH  B
        MOV   A,C       )
        DCR   A         ) Calc offset for oscill.
        ADD   A         ) address
        MOV   C,A       )
        MVI   B,:00
        LXI   H,:FC00   Addr osc. channel 0
        DAD   B         HL = addr current osc
        MOV   M,E       ) Load oscillator
        MOV   M,D       )
        POP   B
 REM
* Block done:
 REM
L1E266  LXI   D,:000E
        POP   H         Get startadr prev. block
        DAD   D         HL pnts to next block
        JMP   :EE73     Run next block
*
* RESTART ENVELOPE:
*
* Gets 1st volume of envelope.
*
* Entry: DE: Points to 2nd byte of envelope pointer
*            of a SCB.
* Exit:  A:  Volume.
*        HL: Address volume field in envelope.
*        BCDEF preserved.
*
L1E267  PUSH  D         Save pntr
        INX   D
        LDAX  D         Get lobyte env pntr
        MOV   L,A       in L
        INX   D
        LDAX  D         Get hibyte env pntr
        MOV   H,A       in H
        POP   D         Restore pntr
        MOV   A,M       Get volume in A
        RET
*
* IF SOUND OF BLOCK IS 'OFF': GOTO NEXT BLOCK:
*
L1E268  INR   C         Update SCB count
        MOV   A,C
        CPI   :04       All blocks done ?
        JNZ   :EF8B     Next block if not
L1E269  POP   H
        RET
*
***************
* BANK RETURN *
***************
*
* Goto ROM bank 0.
*
* Entry: A: Current POROM.
*
BRET    POP   B
        ANI   :3F       Select ROM bank 0
        JMP   :D808     Load PORO/POROM
*
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
*
***************************************
* LOADA: READ VARIABLE TYPE FROM TAPE *
***************************************
*
* Reads 1 byte from tape.
*
* Exit: A: Variable type.
*       DEHL preserved.
*
R1BB    PUSH  H
        PUSH  D
        LXI   H,:013E   Startaddr EBUF
        LXI   D,:013F   Next addr
        CALL  :02D1     Read type from tape
        JNC   :D2B3     Evt run 'LOADING ERROR ..'
        LDA   :013E     Get var.type in A
        POP   D
        POP   H
        RET
*
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
        DATA  :FF
*
*************************
* part of 'EXP' (1E667) *
*************************
*
L1E272  ORA   H
        JP    :E6B8
        JMP   :E6AD
*
*
*
        END
